#define _CRT_SECURE_NO_WARNINGS 1

// 两个空瓶换一个满瓶，那么20个满瓶一共能喝多少瓶
//#include <stdio.h>
//
//int main()
//{
//	int bottles = 20;
//	int total = bottles, empty = bottles;
//
//	while (empty > 1) {
//		total += empty / 2;
//		empty = empty / 2 + empty % 2;
//	}
//
//	printf("%d\n", total);
//
//	return 0;
//}
//
//#include <stdio.h>
//
//int _Func(int total, int empty)
//{
//	if (empty < 2) return total;
//	_Func(total + empty / 2, empty / 2 + empty % 2);
//}
//
//int Func(int money)
//{
//	return _Func(money, money);
//}
//
//int main()
//{
//	int money = 20;
//	int total = Func(money);
//
//	printf("%d\n",total);
//
//	return 0;
//}

//#include <stdio.h>
//
//int main()
//{
//	int sum = 0;
//
//	for (int i = 1; i <= 5; i++) {
//		int a = i;
//		for (int j = 0; j < 5; j++) {
//			sum += a;
//			a = a * 10 + i;
//		}
//	}
//
//	printf("%d\n", sum);
//
//	return 0;
//}

//#include <stdio.h>
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//int main()
//{
//	// 函数指针数组
//	// 指针数组
//	//char* arr[5]; // 字符指针
//	//int* arr[6]; // 整型指针
//
//	int (*pf)(int, int) = Add; // pf是函数指针
//	int (*pfArr[4])(int, int) = { Add, Sub, Mul, Div }; // 存放函数指针的数组 - 函数指针数组
//
//	for (int i = 0; i < 4; i++) {
//		int ret = pfArr[i](6, 2);
//		printf("%d\n", ret);
//	}
//
//	return 0;
//}

// 实现一个计算器
// 这个计算器能够计算整数的加减乘除

//#include <stdio.h>
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//void menu()
//{
//	printf("****************************\n");
//	printf("***** 1.add      2.sub******\n");
//	printf("******3.mul      4.div******\n");
//	printf("***** 0.exit          ******\n");
//	printf("****************************\n");
//
//
//}
//
//int main()
//{
//	int input = 0;
//	int x = 0, y = 0;
//	int ret = 0;
//	int (*pfArr[])(int, int) = {NULL, Add, Sub, Mul, Div};
//
//  函数指针数组的方式解决一下
//  这里的函数指针数组，称之为转移表
//	do
//	{
//		menu();
//		printf("请选择：");
//		scanf("%d", &input);
//
//		if (input == 0) {
//			printf("退出计算器\n");
//		}
//		else if (input >= 1 && input <= 4) {
//			printf("请输入两个操作数：");
//			scanf("%d %d", &x, &y);
//			int ret = pfArr[input](x, y);
//			printf("%d\n", ret);
//		}
//		else printf("输入错误，重新选择\n");
//
//		//switch (input)
//		//{
//		//case 1:
//		//	printf("请输入两个操作数：");
//		//	scanf("%d %d", &x, &y);
//		//	ret = Add(x, y);
//		//	printf("%d\n", ret);
//		//	break;
//		//case 2:
//		//	printf("请输入两个操作数：");
//		//	scanf("%d %d", &x, &y);
//		//	ret = Sub(x, y);
//		//	printf("%d\n", ret);
//		//	break;
//		//case 3:
//		//	printf("请输入两个操作数：");
//		//	scanf("%d %d", &x, &y);
//		//	ret = Mul(x, y);
//		//	printf("%d\n", ret);
//		//	break;
//		//case 4:
//		//	printf("请输入两个操作数：");
//		//	scanf("%d %d", &x, &y);
//		//	ret = Div(x, y);
//		//	printf("%d\n", ret);
//		//	break;
//		//case 0:
//		//	printf("退出计算器\n");
//		//	break;
//		//default:
//		//	printf("输入错误，重新选择\n");
//		//	break;
//		//}
//
//	} while (input);
//
//	return 0;
//}

// 函数指针到底有什么用呢？
// 函数指针可以用来实现回调函数
//
//#include <stdio.h>
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//void menu()
//{
//	printf("****************************\n");
//	printf("***** 1.add      2.sub******\n");
//	printf("******3.mul      4.div******\n");
//	printf("***** 0.exit          ******\n");
//	printf("****************************\n");
//
//
//}
//
//void Calc(int (*pf)(int, int))
//{
//	int x = 0, y = 0;
//	int ret = 0;
//	printf("请输入两个操作数：");
//	scanf("%d %d", &x, &y);
//	ret = pf(x, y);
//	printf("%d\n", ret);
//}
//
//// 回调函数就是一个通过函数指针调用的函数
//// 如果把函数的指针（地址）作为参数传递给另一个参数，当这个指针被用来调用其所指向的函数时
//// 被调用的函数就是回调函数
//int main()
//{
//	int input = 0;
//	//int (*pfArr[])(int, int) = {NULL, Add, Sub, Mul, Div};
//
//    //函数指针数组的方式解决一下
//    //这里的函数指针数组，称之为转移表
//	do
//	{
//		menu();
//		printf("请选择：");
//		scanf("%d", &input);
//
//		//if (input == 0) {
//		//	printf("退出计算器\n");
//		//}
//		//else if (input >= 1 && input <= 4) {
//		//	printf("请输入两个操作数：");
//		//	scanf("%d %d", &x, &y);
//		//	int ret = pfArr[input](x, y);
//		//	printf("%d\n", ret);
//		//}
//		//else printf("输入错误，重新选择\n");
//
//		switch (input)
//		{
//			// 相同（相似）的代码出现了多次，就显得比较冗余
//		case 1:
//			Calc(Add);
//			break;
//		case 2:
//			Calc(Sub);
//			break;
//		case 3:
//			Calc(Mul);
//			break;
//		case 4:
//			Calc(Div);
//			break;
//		case 0:
//			printf("退出计算器\n");
//			break;
//		default:
//			printf("输入错误，重新选择\n");
//			break;
//		}
//
//	} while (input);
//
//	return 0;
//}

// 函数指针的使用：qsort
// qsort是库函数，这个函数可以完成任意类型数据的排序

//#include <stdio.h>
//
//void BubbleSort(int arr[], int sz)
//{
//	for (int i = 0; i < sz - 1; i++) {
//		for (int j = 1; j < sz - i; j++) {
//			if (arr[j] < arr[j - 1]) {
//				int tmp = arr[j];
//				arr[j] = arr[j - 1];
//				arr[j - 1] = tmp;
//			}
//		}
//	}
//}
//
//int main()
//{
//	int arr[10] = { 3,1,5,3,5,6,7,4,1,2 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	BubbleSort(arr, sz);
//	for (int i = 0; i < sz; i++) {
//		printf("%d ", arr[i]);
//	}
//
//	return 0;
//}

//void qsort(
//	void* base, // base 指向了要排序的数组的第一个元素
//	size_t num, // base 指向的数组中的元素个数 （待排序的数组的元素个数）
//	size_t size, // base 指向的数组中，元素的大小，单位是字节
//	int (*compar)(const void* p1, const void* p2) // 函数指针 - 指针指向的函数是用来比较数组中的两个元素的
//	// p1指向元素>p2指向元素，返回＞0
//	// p1指向元素<p2指向元素，返回< 0
//	// 两个整型比较大小直接可以><==
//	// 但是两个结构体的数据不能直接用><==
//);

// 两个字符串不能使用> < ==
// 库函数strcmp用来比较大小，字典序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void PrintArray(int arr[], int sz)
{
	for (int i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}
	putchar('\n');
}

// cmp_int这个函数是用来比较p1和p2指向元素的大小
int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}

void test1()
{
	int arr[10] = { 3,1,5,2,4,6,8,7,0,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	PrintArray(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	PrintArray(arr, sz);
}

// 测试qsort排序结构体数据
struct Stu
{
	char name[20]; // 名字
	int age;
};

// 怎么比较两个结构体数据？
// 按照名字或者年龄，一般是年龄

int cmp_stu_by_age(const void* p1, const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}

int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name , ((struct Stu*)p2)->name);
}

void PrintStu(struct Stu s[], int sz)
{
	for (int i = 0; i < sz; i++) {
		printf("%s\n", s[i].name);
		printf("%d\n", s[i].age);
	}
	putchar('\n');
}

void test2()
{
	struct Stu arr[] = { {"ZhangSan", 20}, {"LiSi", 38}, {"WangWu", 18} };
	int sz = sizeof(arr) / sizeof(arr[0]);

	PrintStu(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);

	PrintStu(arr, sz);
}

int main()
{
	// 将一组整数排序为升序
	/*test1();*/
	test2();

	return 0;
}

// qsort确实可以排序任意类型的数据
// 学会qsort怎么使用
// qsort在使用的时候，需要使用这传递一个函数的地址
// 这个函数用来比较待排序的数组中的2个元素
// 按照参数和返回值的要求实现就行